import * as THREE from 'three'
import {TWEEN} from 'three/examples/jsm/libs/tween.module.min'

class Transitions {
  constructor(renderer, fromScene, toScene, specialEffectsMap) {
    const width = renderer.domElement.offsetWidth, height = renderer.domElement.offsetHeight
    this._scene = new THREE.Scene()
    this._orthographicCamera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, -10, 10)
    this._renderer = renderer

    this.specialEffectsMap = specialEffectsMap || []

    this.useTexture = false
    this.transition = 0
    this.threshold = 0.3
    console.log(this.specialEffectsMap[0])
    const material = new THREE.ShaderMaterial({
      uniforms: {
        tDiffuse1: {value: toScene.renderTarget.texture},
        tDiffuse2: {value: fromScene.renderTarget.texture},
        mixRatio: {value: 0.0},
        threshold: {value: this.threshold},
        useTexture: {value: this.specialEffectsMap[0] ? 1 : 0},
        tMixTexture: {value: this.specialEffectsMap[0]}
      },
      vertexShader: `
				varying vec2 vUv;
				void main() {
				vUv = vec2( uv.x, uv.y );
					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
				}
			`,
      fragmentShader: `
				uniform float mixRatio;
				uniform sampler2D tDiffuse1;
				uniform sampler2D tDiffuse2;
				uniform sampler2D tMixTexture;
				uniform int useTexture;
				uniform float threshold;
				varying vec2 vUv;
				void main() {
				  	vec4 texel1 = texture2D( tDiffuse1, vUv );
				  	vec4 texel2 = texture2D( tDiffuse2, vUv );
				  	if (useTexture==1) {
						vec4 transitionTexel = texture2D( tMixTexture, vUv );
						float r = mixRatio * (1.0 + threshold * 2.0) - threshold;
						float mixf=clamp((transitionTexel.r - r)*(1.0/threshold), 0.0, 1.0);
						gl_FragColor = mix( texel1, texel2, mixf );
				  	} else {
						gl_FragColor = mix( texel2, texel1, mixRatio );
				  	}
				}`
    })

    const geometry = new THREE.PlaneGeometry(width, height)
    const mesh = new THREE.Mesh(geometry, material)
    this._scene.add(mesh)

    this.start = (value) => {
      return new TWEEN.Tween(this).to({transition: value}, 1000).start()
    }

    this.setTextureThreshold = value => material.uniforms.threshold.value = value

    this.useTexture = value => material.uniforms.useTexture.value = value ? 1 : 0

    this.setTexture = i => material.uniforms.tMixTexture.value = this.specialEffectsMap[i]

    this.setScene = (fromTexture, toTexture) => {
      material.uniforms.tDiffuse1.value = toTexture
      material.uniforms.tDiffuse2.value = fromTexture
    }

    this.render = (delta) => {

      TWEEN.update()

      if (this.transition === 0) {

        fromScene.render(delta, false)

      } else if (this.transition === 1) {

        toScene.render(delta, false)

      } else {
        material.uniforms.mixRatio.value = this.transition

        fromScene.render(delta, true)
        toScene.render(delta, true)

        this._renderer.setRenderTarget(null)
        this._renderer.clear()
        this._renderer.render(this._scene, this._orthographicCamera)

      }
    }
  }
}

class CreateScene {
  constructor(renderer, camera, scene) {
    if (!scene) scene = new THREE.Scene()
    const dPR = window.devicePixelRatio
    const renderTargetParameters = {minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat}
    this.renderTarget = new THREE.WebGLRenderTarget(renderer.domElement.offsetWidth * dPR, renderer.domElement.offsetHeight * dPR, renderTargetParameters)

    this.render = (delta, transition = false) => {
      if (transition) {
        renderer.setRenderTarget(this.renderTarget)
        renderer.clear()
        renderer.render(scene, camera)
      } else {
        renderer.setRenderTarget(null)
        renderer.render(scene, camera)
      }
    }
  }
}
